package org.aceor.mddal.config.sharding;

import com.google.common.base.Objects;
import com.google.common.math.LongMath;
import org.aceor.mddal.common.constants.Constants;
import org.aceor.mddal.common.sharding.ShardingFunction;
import org.aceor.mddal.common.utils.DateUtil;
import org.aceor.mddal.common.utils.ValidateUtil;

import java.math.RoundingMode;

/**
 * Created by lxue on 16/3/26.
 */
public abstract class AbstractShardingFunction implements ShardingFunction {

    @Override
    public int executeSharding(Object value) {
        if (!ValidateUtil.isAllNotNullOrEmpty(getShardingColumn(), getStep(), getMaxStepCounts(), getLinearMeasure())) {
            throw new NullPointerException("以下四个参数都不能为空 ==> shardingColumn: " + getShardingColumn() + ",step: " + getStep() + ",maxStepCounts: " + getMaxStepCounts() + ", linearMearsure: " + getLinearMeasure());
        }
        if (null == value) {
            throw new NullPointerException();
        }
        if (Objects.equal(getLinearMeasure(), LinearMeasure.NUMBER)) {
            //数值
            return doExecuteSharding(Long.valueOf(value.toString()));
        } else {
            //时间
            //为了避免这个getTime获取到的毫秒数至少是1000的倍数,这里通过除法来降低级数
            long base = getTimeBase(getLinearMeasure());
            return doExecuteSharding(LongMath.divide(DateUtil.getTime(value.toString()), base, RoundingMode.DOWN));
        }
    }

    private long getTimeBase(LinearMeasure linearMeasure) {
        switch (linearMeasure) {
            case SECOND:
                return Constants.UNIT_SECOND * 1000;
            case MINUTE:
                return Constants.UNIT_MINUTE * 1000;
            case HOUR:
                return Constants.UNIT_HOUR * 1000;
            case DAY:
                return Constants.UNIT_DAY * 1000;
            case MOUTH:
                return Constants.UNIT_MOUTH * 1000;
            case YEAR:
                return Constants.UNIT_YEAR * 1000;
            default:
                throw new IllegalArgumentException();
        }
    }

    protected abstract int doExecuteSharding(Long originValue);

}
